package jxtend.processor.eclipse.visitor.traverser;

import jxtend.processor.eclipse.visitor.ASTNodeScopeFactory;
import jxtend.processor.reflect.ReflectField;

import org.eclipse.jdt.internal.compiler.ASTVisitor;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.Block;
import org.eclipse.jdt.internal.compiler.ast.TryStatement;
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;

@SuppressWarnings("restriction")
public class TryStatementTraverser implements ASTNodeChildrenTraverser {

	private static ReflectField<Block, BlockScope> scopeOfBlock =
			ReflectField.getField(Block.class, BlockScope.class, "scope");

	private static final ReflectField<TryStatement, BlockScope> tryStatementScope =
		ReflectField.getField(TryStatement.class, BlockScope.class, "scope");

	@Override
	public boolean isApplicable(ASTNode node) {
		return (node instanceof TryStatement);
	}

	@Override
	public void traverseChildren(ASTNode node, ASTVisitor visitor, BlockScope scope) {
		TryStatement tryStatement = (TryStatement) node;

		tryStatement.tryBlock.traverse(visitor, tryStatementScope.get(tryStatement));
		if (tryStatement.catchArguments != null) {
			for (int i = 0, max = tryStatement.catchBlocks.length; i < max; i++) {
				Block catchBlock = tryStatement.catchBlocks[i];

				BlockScope catchBlockScope = scopeOfBlock.get(catchBlock);
				if (catchBlockScope == null) {
					catchBlockScope = (BlockScope) ASTNodeScopeFactory.create(node, scopeOfBlock, scope);
					scopeOfBlock.set(catchBlock, catchBlockScope);
				}

				tryStatement.catchArguments[i].traverse(visitor, catchBlockScope);
				tryStatement.catchBlocks[i].traverse(visitor, catchBlockScope);
			}
		}

		Block finallyBlock = tryStatement.finallyBlock;
		if (finallyBlock != null) {
			BlockScope finallyBlockScope = scopeOfBlock.get(finallyBlock);
			if (finallyBlockScope == null) {
				finallyBlockScope = (BlockScope) ASTNodeScopeFactory.create(node, scopeOfBlock, scope);
				scopeOfBlock.set(finallyBlock, finallyBlockScope);
			}

			finallyBlock.traverse(visitor, finallyBlock.scope);
		}
	}

}
